package com.game.framework.message.event;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class GameMessageMappingDispatchManager {

    private Map<Integer, Class<?>> gameMessageClassMap = new HashMap<>();
    private Map<Integer, GameMessageListenerMapping> gameEventMapping = new HashMap<>();

    public GameMessageMappingDispatchManager() {

    }

    public void init(ApplicationContext applicationContext) {
        String[] beanNames = applicationContext.getBeanNamesForAnnotation(GameMessageHandler.class);
        if (beanNames != null && beanNames.length > 0) {
            for (String beanName : beanNames) {
                Object beanObject = applicationContext.getBean(beanName);
                Method[] methods = beanObject.getClass().getMethods();
                if (methods != null && methods.length > 0l) {
                    for (Method method : methods) {
                        GameMessageMapping gameMessageMapping = method.getAnnotation(GameMessageMapping.class);
                        if (gameMessageMapping != null) {
                            Class<?>[] types = method.getParameterTypes();
                            int messageId = getMessageId(types[0]);
                            gameMessageClassMap.put(messageId, types[0]);
                            GameMessageListenerMapping gameMessageHandlerMapping = new GameMessageListenerMapping(beanObject, method);
                            gameEventMapping.put(messageId, gameMessageHandlerMapping);
                        }
                    }
                }
            }
        }
    }
    private int getMessageId(Class<?> clazz) {
        GameMessageMetaData meta = clazz.getAnnotation(GameMessageMetaData.class);
        int messageId = 0;
        if (meta != null) {
            messageId = meta.messageId();
        }
        return messageId;
    }

    public IGameMessage getGameMessageRequestInstance(int messageId) {
        Class<?> clazz = gameMessageClassMap.get(messageId);
        if (clazz == null) {
            log.error("找不到消息号:{}对应的对象类", messageId);
            return null;
        }
        try {
            Object instance = clazz.getConstructor().newInstance();
            return (IGameMessage) instance;
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
                 | NoSuchMethodException | SecurityException e) {
            log.error("消息号为：{} 的对象创建失败", messageId, e);
        }
        return null;
    }

    void addGameEventListenerMapping(Integer messageId, GameMessageListenerMapping gameMessageListenerMapping) {
        gameEventMapping.put(messageId, gameMessageListenerMapping);
    }

    public void sendGameEvent(IGameMessage gameMessage, Object origin) {
        int messageId = gameMessage.getHeader().getMessageId();
        GameMessageListenerMapping messageHandlerMapping = gameEventMapping.get(messageId);
        if (messageHandlerMapping == null) {
            log.error("未找到处理消息：{}的方法", messageId);
            return;
        }
        Object handlerObj = messageHandlerMapping.getBean();
        Method handlerMethod = messageHandlerMapping.getMethod();
        try {
            handlerMethod.invoke(handlerObj, gameMessage);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            log.error("消息号：{}的消息：{}处理失败", messageId, messageHandlerMapping.getClass().getName(), e);
            throw new RuntimeException(e);
        }
    }
}